/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 *
 * $Revision: 11222 $
 * $Id: manager.cpp 11222 2017-10-31 07:56:18Z fuscated $
 * $HeadURL: http://svn.code.sf.net/p/codeblocks/code/branches/release-17.xx/src/sdk/manager.cpp $
 */

/*管理器*/
#include "sdk_precomp.h"

#ifndef CB_PRECOMP
    #include <wx/xrc/xmlres.h>
    #include <wx/fs_zip.h>
    #include <wx/menu.h>

    #include "manager.h" // class's header file
    #include "sdk_events.h"
    #include "cbexception.h"
    #include "projectmanager.h"
    #include "editormanager.h"
    #include "logmanager.h"
    #include "pluginmanager.h"
    #include "toolsmanager.h"
    #include "macrosmanager.h"
    #include "configmanager.h"
    #include "scriptingmanager.h"
    #include "templatemanager.h"
    #include "personalitymanager.h"
    #include "uservarmanager.h"
    #include "filemanager.h"
    #include "globals.h"
    #include "xtra_res.h" // our new ToolBarAddOn handler
#endif

#include <wx/app.h>    // wxTheApp
#include <wx/toolbar.h>
#include <wx/fs_mem.h>


#ifdef PPRCESS_EVENT_PERFORMANCE_MEASURE
// this preprocessor directive can be defined in cbfunctor.h to enable performance measure
// 这个预处理指令能在cbfunctor.h被定义以便性能测量
// demangle C++ names
// 删除C++名称
    #include <cxxabi.h>
// free the memory created by abi::__cxa_demangle
// 释放abi::__cxa_demangle创建的内存
    #include <cstdlib>
#endif // PPRCESS_EVENT_PERFORMANCE_MEASURE

#include "cbcolourmanager.h"
#include "ccmanager.h"
#include "debuggermanager.h"

static Manager* s_ManagerInstance = nullptr;


#ifdef PPRCESS_EVENT_PERFORMANCE_MEASURE
//获取CodeBlocks事件名字符串
static wxString GetCodeblocksEventName(wxEventType type)
{
    wxString name;
    if      (type==cbEVT_APP_STARTUP_DONE) name = _T("cbEVT_APP_STARTUP_DONE");
    else if (type==cbEVT_APP_START_SHUTDOWN) name = _T("cbEVT_APP_START_SHUTDOWN");
    else if (type==cbEVT_APP_ACTIVATED) name = _T("cbEVT_APP_ACTIVATED");
    else if (type==cbEVT_APP_DEACTIVATED) name = _T("cbEVT_APP_DEACTIVATED");
    else if (type==cbEVT_PLUGIN_ATTACHED) name = _T("cbEVT_PLUGIN_ATTACHED");
    else if (type==cbEVT_PLUGIN_RELEASED) name = _T("cbEVT_PLUGIN_RELEASED");
    else if (type==cbEVT_PLUGIN_INSTALLED) name = _T("cbEVT_PLUGIN_INSTALLED");
    else if (type==cbEVT_PLUGIN_UNINSTALLED) name = _T("cbEVT_PLUGIN_UNINSTALLED");
    else if (type==cbEVT_PLUGIN_LOADING_COMPLETE) name = _T("cbEVT_PLUGIN_LOADING_COMPLETE");
    else if (type==cbEVT_EDITOR_CLOSE) name = _T("cbEVT_EDITOR_CLOSE");
    else if (type==cbEVT_EDITOR_OPEN) name = _T("cbEVT_EDITOR_OPEN");
    else if (type==cbEVT_EDITOR_SWITCHED) name = _T("cbEVT_EDITOR_SWITCHED");
    else if (type==cbEVT_EDITOR_ACTIVATED) name = _T("cbEVT_EDITOR_ACTIVATED");
    else if (type==cbEVT_EDITOR_DEACTIVATED) name = _T("cbEVT_EDITOR_DEACTIVATED");
    else if (type==cbEVT_EDITOR_BEFORE_SAVE) name = _T("cbEVT_EDITOR_BEFORE_SAVE");
    else if (type==cbEVT_EDITOR_SAVE) name = _T("cbEVT_EDITOR_SAVE");
    else if (type==cbEVT_EDITOR_MODIFIED) name = _T("cbEVT_EDITOR_MODIFIED");
    else if (type==cbEVT_EDITOR_TOOLTIP) name = _T("cbEVT_EDITOR_TOOLTIP");
    else if (type==cbEVT_EDITOR_TOOLTIP_CANCEL) name = _T("cbEVT_EDITOR_TOOLTIP_CANCEL");
    else if (type==cbEVT_EDITOR_SPLIT) name = _T("cbEVT_EDITOR_SPLIT");
    else if (type==cbEVT_EDITOR_UNSPLIT) name = _T("cbEVT_EDITOR_UNSPLIT");
    else if (type==cbEVT_EDITOR_UPDATE_UI) name = _T("cbEVT_EDITOR_UPDATE_UI");
    else if (type==cbEVT_PROJECT_NEW) name = _T("cbEVT_PROJECT_NEW");
    else if (type==cbEVT_PROJECT_CLOSE) name = _T("cbEVT_PROJECT_CLOSE");
    else if (type==cbEVT_PROJECT_OPEN) name = _T("cbEVT_PROJECT_OPEN");
    else if (type==cbEVT_PROJECT_SAVE) name = _T("cbEVT_PROJECT_SAVE");
    else if (type==cbEVT_PROJECT_ACTIVATE) name = _T("cbEVT_PROJECT_ACTIVATE");
    else if (type==cbEVT_PROJECT_BEGIN_ADD_FILES) name = _T("cbEVT_PROJECT_BEGIN_ADD_FILES");
    else if (type==cbEVT_PROJECT_END_ADD_FILES) name = _T("cbEVT_PROJECT_END_ADD_FILES");
    else if (type==cbEVT_PROJECT_BEGIN_REMOVE_FILES) name = _T("cbEVT_PROJECT_BEGIN_REMOVE_FILES");
    else if (type==cbEVT_PROJECT_END_REMOVE_FILES) name = _T("cbEVT_PROJECT_END_REMOVE_FILES");
    else if (type==cbEVT_PROJECT_FILE_ADDED) name = _T("cbEVT_PROJECT_FILE_ADDED");
    else if (type==cbEVT_PROJECT_FILE_REMOVED) name = _T("cbEVT_PROJECT_FILE_REMOVED");
    else if (type==cbEVT_PROJECT_POPUP_MENU) name = _T("cbEVT_PROJECT_POPUP_MENU");
    else if (type==cbEVT_PROJECT_TARGETS_MODIFIED) name = _T("cbEVT_PROJECT_TARGETS_MODIFIED");
    else if (type==cbEVT_PROJECT_RENAMED) name = _T("cbEVT_PROJECT_RENAMED");
    else if (type==cbEVT_WORKSPACE_CHANGED) name = _T("cbEVT_WORKSPACE_CHANGED");
    else if (type==cbEVT_BUILDTARGET_ADDED) name = _T("cbEVT_BUILDTARGET_ADDED");
    else if (type==cbEVT_BUILDTARGET_REMOVED) name = _T("cbEVT_BUILDTARGET_REMOVED");
    else if (type==cbEVT_BUILDTARGET_RENAMED) name = _T("cbEVT_BUILDTARGET_RENAMED");
    else if (type==cbEVT_BUILDTARGET_SELECTED) name = _T("cbEVT_BUILDTARGET_SELECTED");
    else if (type==cbEVT_PIPEDPROCESS_STDOUT) name = _T("cbEVT_PIPEDPROCESS_STDOUT");
    else if (type==cbEVT_PIPEDPROCESS_STDERR) name = _T("cbEVT_PIPEDPROCESS_STDERR");
    else if (type==cbEVT_PIPEDPROCESS_TERMINATED) name = _T("cbEVT_PIPEDPROCESS_TERMINATED");
    else if (type==cbEVT_THREADTASK_STARTED) name = _T("cbEVT_THREADTASK_STARTED");
    else if (type==cbEVT_THREADTASK_ENDED) name = _T("cbEVT_THREADTASK_ENDED");
    else if (type==cbEVT_THREADTASK_ALLDONE) name = _T("cbEVT_THREADTASK_ALLDONE");
    else if (type==cbEVT_MENUBAR_CREATE_BEGIN) name = _T("cbEVT_MENUBAR_CREATE_BEGIN");
    else if (type==cbEVT_MENUBAR_CREATE_END) name = _T("cbEVT_MENUBAR_CREATE_END");
    else if (type==cbEVT_COMPILER_STARTED) name = _T("cbEVT_COMPILER_STARTED");
    else if (type==cbEVT_COMPILER_FINISHED) name = _T("cbEVT_COMPILER_FINISHED");
    else if (type==cbEVT_COMPILER_SET_BUILD_OPTIONS) name = _T("cbEVT_COMPILER_SET_BUILD_OPTIONS");
    else if (type==cbEVT_CLEAN_PROJECT_STARTED) name = _T("cbEVT_CLEAN_PROJECT_STARTED");
    else if (type==cbEVT_CLEAN_WORKSPACE_STARTED) name = _T("cbEVT_CLEAN_WORKSPACE_STARTED");
    else if (type==cbEVT_DEBUGGER_STARTED) name = _T("cbEVT_DEBUGGER_STARTED");
    else if (type==cbEVT_DEBUGGER_PAUSED) name = _T("cbEVT_DEBUGGER_PAUSED");
    else if (type==cbEVT_DEBUGGER_FINISHED) name = _T("cbEVT_DEBUGGER_FINISHED");
    else name = _("unknown CodeBlocksEvent");

    return name;
}
#endif // PPRCESS_EVENT_PERFORMANCE_MEASURE

Manager::Manager() : m_pAppWindow(nullptr), m_SearchResultLog(nullptr)
{
}

Manager::~Manager()
{
    // 移除所有事件接收器
    for (EventSinksMap::iterator mit = m_EventSinks.begin(); mit != m_EventSinks.end(); ++mit)
    {
        while (mit->second.size())
        {
            delete (*(mit->second.begin()));
            mit->second.erase(mit->second.begin());
        }
    }

    for (DockEventSinksMap::iterator mit = m_DockEventSinks.begin(); mit != m_DockEventSinks.end(); ++mit)
    {
        while (mit->second.size())
        {
            delete (*(mit->second.begin()));
            mit->second.erase(mit->second.begin());
        }
    }

    for (LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.begin(); mit != m_LayoutEventSinks.end(); ++mit)
    {
        while (mit->second.size())
        {
            delete (*(mit->second.begin()));
            mit->second.erase(mit->second.begin());
        }
    }

    for (LogEventSinksMap::iterator mit = m_LogEventSinks.begin(); mit != m_LogEventSinks.end(); ++mit)
    {
        while (mit->second.size())
        {
            delete (*(mit->second.begin()));
            mit->second.erase(mit->second.begin());
        }
    }
}

/*使用主窗口作为参数取管理器*/
Manager* Manager::Get(wxFrame *appWindow)
{
    if (appWindow)
    {
        /*如果Manager对象(实例)变量m_pAppWindow(主应用窗口指针[static])存在*/
        if (Get()->m_pAppWindow) {
            cbThrow(wxT("传递非法参数给Manager::Get()函数"));
        }else{
            Get()->m_pAppWindow = appWindow;
            /*载入资源包里面包含菜单/图标/脚本等资源*/
            LoadResource(_T("manager_resources.zip"));
        }
    }
    return Get();
}

/*默认取管理器函数*/
Manager* Manager::Get()
{
    /*如果全局管理器对象(实例)不存在则分配一个新的管理器对象(实例)*/
    if (!s_ManagerInstance){s_ManagerInstance = new Manager;}
    return s_ManagerInstance;
}

/*释放管理器*/
void Manager::Free()
{
    /*释放全局管理器对象(实例)*/
    delete s_ManagerInstance;
    /*全局管理器变量复位为空指针*/
    s_ManagerInstance = nullptr;
}

/*设置应用程序是否启动状态变量(m_AppStartedUp)*/
void Manager::SetAppStartedUp(bool app_started_up)
{
    m_AppStartedUp = app_started_up;
}

/*设置应用程序是否正在关闭状态变量(m_AppShuttingDown)*/
void Manager::SetAppShuttingDown(bool app_shutting_down)
{
    m_AppShuttingDown = app_shutting_down;
}

/*设置是否使用批构建变量(m_IsBatch)*/
void Manager::SetBatchBuild(bool is_batch)
{
    m_IsBatch = is_batch;
}

/*设置让出CPU时间片(阻塞)状态变量(m_BlockYields)*/
void Manager::BlockYields(bool block)
{
    m_BlockYields = block;
}

/*应用程序正在处理的事件进程*/
void Manager::ProcessPendingEvents()
{
    if (!m_BlockYields && !m_AppShuttingDown) {
        wxTheApp->ProcessPendingEvents();
    }
}

void Manager::Yield()
{
    if (!m_BlockYields && !m_AppShuttingDown) {
        wxTheApp->Yield(true);
    }
}

void Manager::Shutdown()
{
    m_AppShuttingDown = true;

    ToolsManager::Free();
    TemplateManager::Free();
    CCManager::Free();
    PluginManager::Free();
    DebuggerManager::Free();
    ScriptingManager::Free();
    ProjectManager::Free();
    EditorManager::Free();
    PersonalityManager::Free();
    MacrosManager::Free();
    UserVariableManager::Free();
    LogManager::Free();
    CfgMgrBldr::Free();
}

/*处理cb事件*/
bool Manager::ProcessEvent(CodeBlocksEvent& event)
{
    /*正在关闭应用,返回*/
    if (IsAppShuttingDown()) {
        return false;
    }
    /*事件接收器映射图[相当存储数组]迭代器*/
    EventSinksMap::iterator mit = m_EventSinks.find(event.GetEventType());
    if (mit != m_EventSinks.end())
    {
        for (EventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it)
        {
#ifdef PPRCESS_EVENT_PERFORMANCE_MEASURE
            wxStopWatch sw;
#endif // PPRCESS_EVENT_PERFORMANCE_MEASURE

            (*it)->Call(event);

#ifdef PPRCESS_EVENT_PERFORMANCE_MEASURE
            /*仅打印运行时间超过10毫秒的处理程序*/
            if(sw.Time() > 10)
            {
                // 将C++源程序标识符(original C++ source identifier)
                // 转换成C++ ABI标识符(C++ ABI identifier)的过程称为mangle;
                // 相反的过程称为demangle.
                // 获取一个被编译过的C++函数的名称
                const char *p = (*it)->GetTypeName();
                int   status;
                char *realname;
                realname = abi::__cxa_demangle(p, 0, 0, &status);
                wxString msg;

                /*如果这个未被编译过C++函数名是(可以访问)成功则真名不是NULL*/
                if (realname != 0)
                {
                    msg = wxString::FromUTF8(realname);
                    free(realname);
                }else{
                    msg = wxString::FromUTF8(p);
                }

                wxEventType type=event.GetEventType();
                msg << GetCodeblocksEventName(type);
                Manager::Get()->GetLogManager()->DebugLog(F(wxT("%s 运行 %ld 微妙"), msg.wx_str(), sw.Time()));
            }
#endif // PPRCESS_EVENT_PERFORMANCE_MEASURE
        }
    }
    return true;
}

/*事件处理(cb dock Evt)*/
bool Manager::ProcessEvent(CodeBlocksDockEvent& event)
{
    if (IsAppShuttingDown()) { return false; }

    DockEventSinksMap::iterator mit = m_DockEventSinks.find(event.GetEventType());
    if (mit != m_DockEventSinks.end())
    {
        for (DockEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it) { (*it)->Call(event); }
    }
    return true;
}

/*事件处理(cb layout Evt)*/
bool Manager::ProcessEvent(CodeBlocksLayoutEvent& event)
{
    if (IsAppShuttingDown()) { return false; }

    LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.find(event.GetEventType());
    if (mit != m_LayoutEventSinks.end())
    {
        for (LayoutEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it) { (*it)->Call(event); }
    }
    return true;
}

/*事件处理(cb log Evt)*/
bool Manager::ProcessEvent(CodeBlocksLogEvent& event)
{
    if (IsAppShuttingDown()) { return false; }

    LogEventSinksMap::iterator mit = m_LogEventSinks.find(event.GetEventType());
    if (mit != m_LogEventSinks.end())
    {
        for (LogEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it) { (*it)->Call(event); }
    }
    return true;
}

bool Manager::IsAppShuttingDown()
{
    return m_AppShuttingDown;
}

bool Manager::IsAppStartedUp()
{
    return m_AppStartedUp;
}

/*初始化资源文件*/
void Manager::InitXRC(bool force)
{
    static bool xrcok = false;
    if (!xrcok || force)
    {
        wxFileSystem::AddHandler(new wxZipFSHandler);
        wxXmlResource::Get()->InsertHandler(new wxToolBarAddOnXmlHandler);
        wxXmlResource::Get()->InitAllHandlers();

        xrcok = true;
    }
}

void Manager::LoadXRC(wxString relpath)
{
    LoadResource(relpath);
}

/*载入菜单(主菜单)资源*/
wxMenuBar *Manager::LoadMenuBar(wxString resid,bool createonfailure)
{
    Get()->GetLogManager()->DebugLog(wxString::Format(wxT("载入菜单栏资源[编号:%s"),resid.wx_str()));
    wxMenuBar *m = wxXmlResource::Get()->LoadMenuBar(resid);
    if (!m && createonfailure) m = new wxMenuBar();
    return m;
}

/*载入菜单(主菜单)资源*/
wxMenu *Manager::LoadMenu(wxString menu_id,bool createonfailure)
{
    Get()->GetLogManager()->DebugLog(wxString::Format(wxT("载入菜单编号:%s"),menu_id.wx_str()));
    wxMenu *m = wxXmlResource::Get()->LoadMenu(menu_id);
    if (!m && createonfailure){ m = new wxMenu(wxT("失败载入菜单!"));}
    return m;
}

/*载入工具条资源*/
wxToolBar *Manager::LoadToolBar(wxFrame *parent,wxString resid,bool defaultsmall)
{
    if (!parent) { return nullptr; }
    wxToolBar *tb = wxXmlResource::Get()->LoadToolBar(parent,resid);
    if (!tb)
    {
        int flags = wxTB_HORIZONTAL;

        if (platform::WindowsVersion() < platform::winver_WindowsXP) { flags |= wxTB_FLAT; }

        tb = parent->CreateToolBar(flags, wxID_ANY);
        tb->SetToolBitmapSize(defaultsmall ? wxSize(16, 16) : wxSize(22, 22));
    }

    return tb;
}

/*载入空工具条资源*/
wxToolBar* Manager::CreateEmptyToolbar()
{
    bool smallToolBar = Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/toolbar_size"), true);

    wxSize size = smallToolBar ? wxSize(16, 16) : (platform::macosx ? wxSize(32, 32) : wxSize(22, 22));
    wxToolBar* toolbar = new wxToolBar(GetAppFrame(), -1, wxDefaultPosition, size, wxTB_FLAT | wxTB_NODIVIDER);
    toolbar->SetToolBitmapSize(size);

    return toolbar;
}

void Manager::AddonToolBar(wxToolBar* toolBar,wxString resid)
{
    if (!toolBar){return;}
    wxXmlResource::Get()->LoadObject(toolBar,nullptr,resid,_T("wxToolBarAddOn"));
}

bool Manager::isToolBar16x16(wxToolBar* toolBar)
{
    /*缺省为小图标*/
    if (!toolBar) return true;
    wxSize mysize=toolBar->GetToolBitmapSize();
    return (mysize.GetWidth()<=16 && mysize.GetHeight()<=16);
}

wxFrame* Manager::GetAppFrame() const
{
    return m_pAppWindow;
}

wxWindow* Manager::GetAppWindow() const
{
    return (wxWindow*)m_pAppWindow;
}

ProjectManager* Manager::GetProjectManager() const
{
    return ProjectManager::Get();
}

EditorManager* Manager::GetEditorManager() const
{
    return EditorManager::Get();
}

LogManager* Manager::GetLogManager() const
{
    return LogManager::Get();
}

PluginManager* Manager::GetPluginManager() const
{
    return PluginManager::Get();
}

ToolsManager* Manager::GetToolsManager() const
{
    return ToolsManager::Get();
}

MacrosManager* Manager::GetMacrosManager() const
{
    return MacrosManager::Get();
}

PersonalityManager* Manager::GetPersonalityManager() const
{
    return PersonalityManager::Get();
}

UserVariableManager* Manager::GetUserVariableManager() const
{
    return UserVariableManager::Get();
}

ScriptingManager* Manager::GetScriptingManager() const
{
    return ScriptingManager::Get();
}

ConfigManager* Manager::GetConfigManager(const wxString& name_space) const
{
    return CfgMgrBldr::GetConfigManager(name_space);
}

FileManager* Manager::GetFileManager() const
{
    return FileManager::Get();
}

DebuggerManager* Manager::GetDebuggerManager() const
{
    return DebuggerManager::Get();
}

ColourManager* Manager::GetColourManager() const
{
    return ColourManager::Get();
}

CCManager* Manager::GetCCManager() const
{
    return CCManager::Get();
}

bool Manager::LoadResource(const wxString& file)
{
    wxString resourceFile = ConfigManager::LocateDataFile(file, sdDataGlobal | sdDataUser);

    wxString MsgErrLog=wxString::Format(wxT("管理器访问[XRC]资源文件%s 失败."),resourceFile.wx_str());
    Get()->GetLogManager()->Log(wxString::Format(wxT("载入资源文件:%s"),resourceFile));

    wxString memoryFile = _T("memory:") + file;

    if (wxFile::Access(resourceFile, wxFile::read) == false)
    {
        Get()->GetLogManager()->DebugLog(MsgErrLog);
        return false;
    }

    /*下面的代码强制重新加载资源,当前未使用...*/
    /*{wxMemoryFSHandler::RemoveFile(file);}*/
    /*卸载同名的旧资源*/

    // #if wxABI_VERSION > 20601
    // wxXmlResource::Get()->Unload(memoryFile);
    // #endif

    wxFile f(resourceFile, wxFile::read);
    char *buf = nullptr;

    try
    {
        /*文件的偏移量长度？gnu-x是 # define __SQUAD_TYPE		long int/__OFF64_T_TYPE*/
        size_t len = f.Length();
        buf = new char[len];
        f.Read(buf, len);
        {
            wxMemoryFSHandler::AddFile(file, buf, len);
        }

        if (!wxXmlResource::Get()->Load(memoryFile)) { Get()->GetLogManager()->DebugLog(MsgErrLog); }
        delete[] buf;
        return true;
    }
    catch (...)
    {
        delete[] buf;
        Get()->GetLogManager()->DebugLog(MsgErrLog);
        return false;
    }
}

/*命令行参数解释器*/
wxCmdLineParser* Manager::GetCmdLineParser()
{
    return &m_CmdLineParser;
}

void Manager::RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksEvent>* functor)
{
    m_EventSinks[eventType].push_back(functor);
}

void Manager::RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksDockEvent>* functor)
{
    m_DockEventSinks[eventType].push_back(functor);
}

void Manager::RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksLayoutEvent>* functor)
{
    m_LayoutEventSinks[eventType].push_back(functor);
}

void Manager::RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksLogEvent>* functor)
{
    m_LogEventSinks[eventType].push_back(functor);
}

/*移除事件接收器*/
void Manager::RemoveAllEventSinksFor(void* owner)
{
    for (EventSinksMap::iterator mit = m_EventSinks.begin(); mit != m_EventSinks.end(); ++mit)
    {
        EventSinksArray::iterator it = mit->second.begin();
        bool endIsInvalid = false;
        while (!endIsInvalid && it != mit->second.end())
        {
            if ((*it) && (*it)->GetThis() == owner)
            {
                EventSinksArray::iterator it2 = it++;
                endIsInvalid = it == mit->second.end();
                delete (*it2);
                mit->second.erase(it2);
            }
            else
                ++it;
        }
    }

    for (DockEventSinksMap::iterator mit = m_DockEventSinks.begin(); mit != m_DockEventSinks.end(); ++mit)
    {
        DockEventSinksArray::iterator it = mit->second.begin();
        bool endIsInvalid = false;
        while (!endIsInvalid && it != mit->second.end())
        {
            if ((*it) && (*it)->GetThis() == owner)
            {
                DockEventSinksArray::iterator it2 = it++;
                endIsInvalid = it == mit->second.end();
                delete (*it2);
                mit->second.erase(it2);
            }
            else
                ++it;
        }
    }

    for (LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.begin(); mit != m_LayoutEventSinks.end(); ++mit)
    {
        LayoutEventSinksArray::iterator it = mit->second.begin();
        bool endIsInvalid = false;
        while (!endIsInvalid && it != mit->second.end())
        {
            if ((*it) && (*it)->GetThis() == owner)
            {
                LayoutEventSinksArray::iterator it2 = it++;
                endIsInvalid = it == mit->second.end();
                delete (*it2);
                mit->second.erase(it2);
            }
            else
                ++it;
        }
    }

    for (LogEventSinksMap::iterator mit = m_LogEventSinks.begin(); mit != m_LogEventSinks.end(); ++mit)
    {
        LogEventSinksArray::iterator it = mit->second.begin();
        bool endIsInvalid = false;
        while (!endIsInvalid && it != mit->second.end())
        {
            if ((*it) && (*it)->GetThis() == owner)
            {
                LogEventSinksArray::iterator it2 = it++;
                endIsInvalid = it == mit->second.end();
                delete (*it2);
                mit->second.erase(it2);
            }
            else
                ++it;
        }
    }
}

bool            Manager::m_AppShuttingDown = false;
bool            Manager::m_AppStartedUp    = false;
bool            Manager::m_BlockYields     = false;
bool            Manager::m_IsBatch         = false;
wxCmdLineParser Manager::m_CmdLineParser;
